﻿using AutoMapper;
using IOA.MES.DataAccess.Entity;
using IOA.MES.DataAccess.Enum;
using IOA.MES.DataAccess.VModel;
using IOA.MES.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using IOA.Utils;
using IOA.MES.Log.DataAccess.VModel;
using IOA.MES.Log.Business;
using NLog;

namespace IOA.MES.Business
{
    /// <summary>
    /// 出库管理（错误代码：115001）
    /// </summary>
    public class OutboundMgr
    {
        private Logger logger = LogManager.GetCurrentClassLogger();
        private MESContext mesDb = new MESContext("MES");

        /// <summary>
        /// 出库操作
        /// </summary>
        /// <param name="model">出库单</param>
        /// <param name="packNos">打包列表</param>
        public void Outbound(VOutboundPack model)
        {
            var outbound = mesDb.Outbounds.AsNoTracking().FirstOrDefault(_ => _.OutboundNo == model.OutboundNo && _.Valid);
            if (outbound == null)
            {
                throw new MultiLanBizException(115002);// "出库任务不存在");
            }
            else if (outbound.OutboundBy > 0 && outbound.OutboundBy != model.ModifyBy)
            {
                throw new MultiLanBizException(115003);// "该出库单已有其他人操作");
            }
            else if (outbound.Status == OutboundStatus.Canceled)
            {
                throw new MultiLanBizException(115004);// "当前出库任务已被取消");
            }
            else if (outbound.Status == OutboundStatus.Finished)
            {
                throw new MultiLanBizException(115005);// "当前出库任务已完成");
            }

            var pack = mesDb.Packs.AsNoTracking().FirstOrDefault(_ => _.PackNo == model.PackNo && _.Valid);
            if (pack == null)
            {
                throw new MultiLanBizException(102008, model.PackNo);//包装不存在
            }
            var outboundPack = mesDb.OutboundPacks.AsNoTracking().FirstOrDefault(_ => _.OutboundNo == model.OutboundNo && _.PackNo == model.PackNo && _.Valid);
            if (outboundPack == null)
            {
                throw new MultiLanBizException(115006, model.PackNo);// $"箱号不在当前出库任务中：
            }
            else if (outboundPack.Outbounded)
            {
                throw new MultiLanBizException(115007, model.PackNo);// $"当前箱号已出库，不可重复操作：
            }
            mesDb.Packs.Attach(pack);
            pack.StockStatus = PackStockStatus.Outbound;
            pack.ModifyBy = model.ModifyBy;
            pack.ModifyTime = DateTime.Now;

            mesDb.OutboundPacks.Attach(outboundPack);
            outboundPack.Outbounded = true;
            outboundPack.ModifyBy = model.ModifyBy;
            outboundPack.ModifyTime = DateTime.Now;

            mesDb.Outbounds.Attach(outbound);
            outbound.OutboundedQuantity = outbound.OutboundedQuantity + 1;
            if (outbound.Quantity == outbound.OutboundedQuantity)
            {
                outbound.Status = OutboundStatus.Finished;
            }
            else if (outbound.Status == OutboundStatus.UnFinished)
            {
                outbound.Status = OutboundStatus.UnFinished;
                outbound.OutboundBy = model.ModifyBy;
                outbound.OutboundTime = DateTime.Now;
            }
            outbound.ModifyBy = model.ModifyBy;
            outbound.ModifyTime = DateTime.Now;

            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    #region 修改包装库位
                    var components = mesDb.Components.AsNoTracking().Where(_ => _.PackNo == model.PackNo && _.Valid).ToList();
                    components.ForEach(_ =>
                    {
                        mesDb.Components.Attach(_);
                        _.WarehouseCode = string.Empty;
                        _.WarehouseName = string.Empty;
                        _.WarehouseAreaCode = string.Empty;
                        _.WarehouseAreaName = string.Empty;
                        _.Location = string.Empty;
                    });
                    mesDb.SaveChanges();

                    var users = new UserMgr().QueryUsers(new List<int> { model.CreateBy });
                    var logs = components.Select(_ => new VOprLog
                    {
                        SubjectType = "组件",
                        SubjectNo = _.BarCode,
                        LogName = "组件出库",
                        LogStatus = "正常",
                        OpeatorId = model.CreateBy,
                        OpeatorName = users.FirstOrDefault()?.TrueName,
                        LogContent = $"组件出库，出库单号：{outbound.OutboundNo}，仓库：{_.WarehouseAreaName}，库区：{_.WarehouseAreaName}，库位：{_.Location}",
                        LogTime = DateTime.Now,
                        CreateBy = model.CreateBy
                    }).ToList();
                    new OprLogMgr().AddLogs(logs);
                    #endregion
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"出库操作异常，出库单号：{model.OutboundNo}，异常信息：{ex.Message}");
                }
            });
        }

        /// <summary>
        /// 查询出库列表
        /// </summary>
        /// <param name="page">页面索引</param>
        /// <param name="limit">页面容量</param>
        /// <param name="total"></param>
        /// <param name="warehouseCode">仓库代码</param>
        /// <param name="deliveryNo">发货单号</param>
        /// <param name="outboundNo">出库单号</param>
        /// <param name="startDate">开始日期</param>
        /// <param name="endDate">截止日期</param>
        /// <returns>出库单列表</returns>
        public List<VOutbound> QueryOutbounds(int page, int limit, out int total, string warehouseCode, string deliveryNo, string outboundNo, DateTime startDate, DateTime endDate)
        {
            endDate = endDate.AddDays(1);
            var query = from task in mesDb.Outbounds.Where(_ => _.CreateTime >= startDate && _.CreateTime < endDate && _.Valid)
                        select task;
            if (!string.IsNullOrWhiteSpace(warehouseCode))
            {
                query = query.Where(_ => _.WarehouseCode == warehouseCode);
            }
            if (!string.IsNullOrWhiteSpace(deliveryNo))
            {
                query = query.Where(_ => _.OutboundTypeNo.Contains(deliveryNo));
            }
            if (!string.IsNullOrWhiteSpace(outboundNo))
            {
                query = query.Where(_ => _.OutboundNo.Contains(outboundNo));
            }

            total = query.Count();
            var entities = query.OrderByDescending(_ => _.PkId).Skip((page - 1) * limit).Take(limit);
            var models = Mapper.Map<List<VOutbound>>(entities);
            var userIds = models.Select(_ => _.CreateBy).ToList();
            userIds.AddRange(models.Select(_ => _.OutboundBy));
            var users = new UserMgr().QueryUsers(userIds.Distinct().ToList());
            models.ForEach(task =>
            {
                task.CNOutboundBy = users.FirstOrDefault(_ => _.PkId == task.OutboundBy)?.TrueName;
                task.CNCreateBy = users.FirstOrDefault(_ => _.PkId == task.CreateBy)?.TrueName;
            });
            return models;
        }

        /// <summary>
        /// 获取出库单对象
        /// </summary>
        /// <param name="outboundNo">出库单号</param>
        /// <returns>出库单对象</returns>
        public VOutbound GetOutbound(string outboundNo)
        {
            var entity = mesDb.Outbounds.AsNoTracking().FirstOrDefault(_ => _.OutboundNo == outboundNo && _.Valid);
            if (entity == null)
            {
                return null;
            }
            var model = Mapper.Map<VOutbound>(entity);
            var userIds = new[] { model.CreateBy, model.OutboundBy }.Distinct().ToList();
            var users = new UserMgr().QueryUsers(userIds);
            model.CNCreateBy = users.FirstOrDefault(_ => _.PkId == model.CreateBy)?.TrueName;
            model.CNOutboundBy = users.FirstOrDefault(_ => _.PkId == model.OutboundBy)?.TrueName;

            var outboundPacks = mesDb.OutboundPacks.AsNoTracking().Where(_ => _.OutboundNo == model.OutboundNo && _.Valid).ToList();
            model.Products = Mapper.Map<List<VOutboundPack>>(outboundPacks);

            var packNos = outboundPacks.Select(_ => _.PackNo).Distinct().ToList();
            var packs = Mapper.Map<List<VPack>>(mesDb.Packs.AsNoTracking().Where(_ => packNos.Contains(_.PackNo) && _.Valid).ToList());
            packs.ForEach(pack =>
            {
                pack.WarehouseCode = outboundPacks.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, pack.PackNo))?.WarehouseCode;
                pack.WarehouseName = outboundPacks.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, pack.PackNo))?.WarehouseName;
                pack.AreaCode = outboundPacks.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, pack.PackNo))?.AreaCode;
                pack.AreaName = outboundPacks.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, pack.PackNo))?.AreaName;
                pack.Location = outboundPacks.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, pack.PackNo))?.Location;
                pack.Outbounded = outboundPacks.FirstOrDefault(_ => StringUtils.Equals(_.PackNo, pack.PackNo))?.Outbounded ?? false;
            });
            model.Packs = packs;

            return model;
        }

        /// <summary>
        /// 查询出库任务列表
        /// </summary>
        /// <param name="pageIndex">页面索引</param>
        /// <param name="pageSize">页面容量</param>
        /// <param name="total">总数</param>
        /// <param name="warehouseCode">仓库代码</param>
        /// <param name="outboundStatus">出库状态</param>
        /// <param name="outboundBy">出库人</param>
        /// <returns>出库单列表</returns>
        public List<VOutbound> QueryOutbounds(int pageIndex, int pageSize, out int total, string warehouseCode, OutboundStatus[] outboundStatus, int outboundBy)
        {
            var query = from task in mesDb.Outbounds.Where(_ => _.WarehouseCode == warehouseCode && _.Valid)
                        select task;
            if (outboundStatus.Any())
            {
                query = query.Where(_ => outboundStatus.Contains(_.Status));
            }
            if (outboundBy > 0)
            {
                query = query.Where(_ => _.OutboundBy == outboundBy);
            }

            total = query.Count();
            var entities = query.OrderByDescending(_ => _.PkId).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            var models = Mapper.Map<List<VOutbound>>(entities);

            var userIds = models.Select(_ => _.CreateBy).ToList();
            userIds.AddRange(models.Select(_ => _.OutboundBy));
            userIds = userIds.Distinct().ToList();
            var users = new UserMgr().QueryUsers(userIds);

            models.ForEach(task =>
            {
                task.CNCreateBy = users.FirstOrDefault(_ => _.PkId == task.CreateBy)?.TrueName;
                task.CNOutboundBy = users.FirstOrDefault(_ => _.PkId == task.OutboundBy)?.TrueName;
            });
            return models;
        }
    }
}
